/**
 *
 * cpulimit - a CPU limiter for Linux
 *
 * Copyright (C) 2005-2012, by:  Angelo Marletta <angelo dot marletta at gmail dot com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <stdlib.h>
#include <string.h>

#include "list.h"

#define EMPTYLIST NULL

void init_list(struct list *l,int keysize) {
    l->first=l->last=NULL;
    l->keysize=keysize;
    l->count=0;
}

struct list_node *add_elem(struct list *l,void *elem) {
    struct list_node *newnode=(struct list_node *)malloc(sizeof(struct list_node));
    newnode->data=elem;
    newnode->previous=l->last;
    newnode->next=NULL;
    if (l->count==0) {
        l->first=l->last=newnode;
    } else {
        l->last->next=newnode;
        l->last=newnode;
    }
    l->count++;
    return newnode;
}

void delete_node(struct list *l,struct list_node *node) {
    if (l->count==1) {
        l->first=l->last=NULL;
    } else if (node==l->first) {
        node->next->previous=NULL;
        l->first=node->next;
    } else if (node==l->last) {
        node->previous->next=NULL;
        l->last=node->previous;
    } else {
        node->previous->next=node->next;
        node->next->previous=node->previous;
    }
    l->count--;
    free(node);
}

void destroy_node(struct list *l,struct list_node *node) {
    free(node->data);
    node->data=NULL;
    delete_node(l,node);
}

int is_empty_list(struct list *l) {
    return (l->count==0?TRUE:FALSE);
}

int get_list_count(struct list *l) {
    return l->count;
}

void *first_elem(struct list *l) {
    return l->first->data;
}

struct list_node *first_node(struct list *l) {
    return l->first;
}

void *last_elem(struct list *l) {
    return l->last->data;
}

struct list_node *last_node(struct list *l) {
    return l->last;
}

struct list_node *xlocate_node(struct list *l,void *elem,int offset,int length) {
    struct list_node *tmp;
    tmp=l->first;
    while (tmp!=NULL) {
        if (!memcmp((char *)tmp->data+offset,elem,length==0?l->keysize:length)) {
            return (tmp);
        }
        tmp=tmp->next;
    }
    return EMPTYLIST;
}

struct list_node *locate_node(struct list *l,void *elem) {
    return (xlocate_node(l,elem,0,0));
}

void *xlocate_elem(struct list *l,void *elem,int offset,int length) {
    struct list_node *node=xlocate_node(l,elem,offset,length);
    return (node==NULL?NULL:node->data);
}

void *locate_elem(struct list *l,void *elem) {
    return (xlocate_elem(l,elem,0,0));
}

void clear_list(struct list *l) {
    while (l->first!=EMPTYLIST) {
        struct list_node *tmp;
        tmp=l->first;
        l->first=l->first->next;
        free(tmp);
        tmp=NULL;
    }
    l->last=EMPTYLIST;
    l->count=0;
}

void destroy_list(struct list *l) {
    while (l->first!=EMPTYLIST) {
        struct list_node *tmp;
        tmp=l->first;
        l->first=l->first->next;
        free(tmp->data);
        tmp->data=NULL;
        free(tmp);
        tmp=NULL;
    }
    l->last=EMPTYLIST;
    l->count=0;
}
